﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Moon.Sql
{
    public abstract class DeleteableProvide<T> : IDeleteable<T>
    {
        protected IDatabase Database;
        protected IExpression ExpressionProvideObj;
        protected SqlBuilderResult _Where;
        protected MapperTable MasterTable;
        protected string MasterTableName;
        protected object[] InParams;
        protected int? _Limit;
        protected bool IsQuote = true;

        public DeleteableProvide(IDatabase _Database)
        {
            Database = _Database;

            MasterTable = ClassMapper.Mapping<T>();
            MasterTableName = MasterTable.TableName;

            ExpressionProvideObj = new ExpressionProvide(Database.SqlDialect, MasterTable);
        }

        public IDeleteable<T> Deleteable()
        {
            return this;
        }

        public IDeleteable<T> Deleteable(params object[] pks)
        {
            InParams = pks;
            return this;
        }

        public IDeleteable<T> TableName(string tableName = null, bool isQuote = true)
        {
            IsQuote = isQuote;
            if (!string.IsNullOrWhiteSpace(tableName))
            {
                MasterTableName = tableName;
            }
            return this;
        }

        public IDeleteable<T> Where(Expression<Func<T, bool>> where)
        {
            _Where = ExpressionProvideObj.ExpressionRouter(where);
            return this;
        }

        public int Execute()
        {
            SqlBuilderResult result = ToSql();
            return Database.Execute(result.Sql, result.DynamicParameters);
        }

        public async Task<int> ExecuteAsync()
        {
            SqlBuilderResult result = ToSql();
            return await Database.ExecuteAsync(result.Sql, result.DynamicParameters);
        }

        public int Truncate()
        {
            return Database.Execute($"truncate table {MasterTableName}");
        }

        public async Task<int> TruncateAsync()
        {
            return await Database.ExecuteAsync($"truncate table {MasterTableName}");
        }

        public IDeleteable<T> Limit(int limit)
        {
            _Limit = limit;
            return this;
        }

        public abstract SqlBuilderResult ToSql();

        public SqlBuilderResult GetSqlParam()
        {
            if (_Where == null && InParams == null)
            {
                throw new Exception("condition error");
            }
            DynamicParameters dynamicParameters = new DynamicParameters();
            string whereSql = "";
            if (_Where != null)
            {
                whereSql = _Where.Sql;
            }
            else
            {
                if (InParams != null && InParams.Length > 0)
                {
                    //多个主键无法删除
                    var array = MasterTable.Properties.Where(i => i.IsPrimaryKey);
                    if (array != null && array.Count() == 1)
                    {
                        PropertyMap propertyMap = array.FirstOrDefault();
                        whereSql = Database.SqlDialect.SetSqlName(propertyMap.ColumnName) + " in ({0})";
                        string parameterSql = string.Join(",", InParams.Select(i => $"'{i}'"));
                        if (InParams[0].GetType().IsArray)
                        {
                            parameterSql = string.Join(",", (((Array)InParams[0]).OfType<object>()).Select(i => $"'{i}'"));
                        }
                        if (string.IsNullOrWhiteSpace(parameterSql))
                        {
                            throw new Exception("parameter data is empty");
                        }
                        whereSql = string.Format(whereSql, parameterSql);
                    }
                    else
                    {
                        throw new Exception("primary key is empty or has more than one primary key");
                    }
                }
            }
            if (_Where != null)
            {
                dynamicParameters.Add(_Where.DynamicParameters);
            }
            return new SqlBuilderResult()
            {
                DynamicParameters = dynamicParameters,
                Sql = whereSql
            };
        }
    }
}
